package com.hh.controller;

import cn.hutool.core.collection.CollUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.hh.annotation.AuthCheck;
import com.hh.annotation.Loggable;
import com.hh.common.BaseResponse;
import com.hh.common.ErrorCode;
import com.hh.common.ResultUtils;
import com.hh.constant.UserConstant;
import com.hh.entity.domain.User;
import com.hh.entity.dto.user.*;
import com.hh.entity.vo.LoginUserVO;
import com.hh.entity.vo.UserVO;
import com.hh.exception.BusinessException;
import com.hh.exception.ThrowUtils;
import com.hh.service.MessageService;
import com.hh.service.UserService;
import com.hh.utils.ExcelUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.util.*;

import static com.hh.constant.UserConstant.DEFAULT_PASSWORD;

/**
 * 用户控制器
 * 提供用户注册、登录、信息管理等相关接口
 * 包含用户信息的增删改查、签到记录、数据导入导出等功能
 *
 * @author hanhui
 */
@RestController
@RequestMapping("/user")
@Slf4j
public class UserController {

    @Resource
    ExcelUtil excelUtil;
    @Resource
    private UserService userService;
    @Resource
    private MessageService messageService;

    /**
     * 用户注册
     * 处理用户注册请求，包含参数校验、用户创建和系统通知发送
     *
     * @param userRegisterRequest 用户注册信息，包含账号、密码和确认密码
     * @return 返回注册用户的ID
     */
    @Loggable
    @PostMapping("/register")
    public BaseResponse<Long> userRegister(@RequestBody UserRegisterRequest userRegisterRequest) {
        if (userRegisterRequest == null) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        String userAccount = userRegisterRequest.getUserAccount();
        String userPassword = userRegisterRequest.getUserPassword();
        String checkPassword = userRegisterRequest.getCheckPassword();
        if (StringUtils.isAnyBlank(userAccount, userPassword, checkPassword)) {
            throw new BusinessException(ErrorCode.DATA_NULL_ERROR);
        }
        long result = userService.userRegister(userAccount, userPassword, checkPassword);
        User newUser = userService.getOne(new QueryWrapper<User>().eq("userAccount", userAccount));
        // 发送系统通知
        String content = String.format("欢迎注册，%s ！", newUser.getUserName());
        messageService.sendSystemMessage(content);
        return ResultUtils.success(result);
    }

    /**
     * 用户登录
     * 处理用户登录请求，验证用户身份并返回登录信息
     *
     * @param userLoginRequest 用户登录请求，包含账号和密码
     * @param request          HTTP请求对象，用于会话管理
     * @return 返回登录用户的信息视图对象
     */
    @Loggable
    @PostMapping("/login")
    public BaseResponse<LoginUserVO> userLogin(@RequestBody UserLoginRequest userLoginRequest, HttpServletRequest request) {
        if (userLoginRequest == null) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        String userAccount = userLoginRequest.getUserAccount();
        String userPassword = userLoginRequest.getUserPassword();
        if (StringUtils.isAnyBlank(userAccount, userPassword)) {
            throw new BusinessException(ErrorCode.PARAMS_NULL);
        }
        LoginUserVO loginUserVO = userService.userLogin(userAccount, userPassword, request);
        return ResultUtils.success(loginUserVO);
    }

    /**
     * 用户登出
     * 处理用户登出请求，清除用户登录状态
     *
     * @param request HTTP请求对象，用于获取会话信息
     * @return 返回登出操作是否成功
     */
    @GetMapping("/logout")
    public BaseResponse<Boolean> userLogout(HttpServletRequest request) {
        if (request == null) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        boolean result = userService.userLogout(request);
        return ResultUtils.success(result);
    }

    /**
     * 获取当前登录用户信息
     * 从会话中获取当前登录用户的信息并返回
     *
     * @param request HTTP请求对象，用于获取登录用户信息
     * @return 返回当前登录用户的信息视图对象
     */
    @GetMapping("/getLoginUser")
    public BaseResponse<LoginUserVO> getLoginUser(HttpServletRequest request) {
        User loginUser = userService.getLoginUser(request);
        return ResultUtils.success(userService.getLoginUserVO(loginUser));
    }

    /**
     * 获取指定用户信息
     * 根据用户ID获取用户信息，如果是当前登录用户则返回详细信息
     *
     * @param userId  要查询的用户ID
     * @param request HTTP请求对象，用于获取当前登录用户信息
     * @return 返回用户信息视图对象
     */
    @GetMapping("/{userId}/info")
    public BaseResponse<UserVO> getUserVO(@PathVariable Long userId, HttpServletRequest request) {
        // 获取当前登录用户
        User loginUser = userService.getLoginUser(request);
        // 判断参数是否为空
        ThrowUtils.throwIf(userId == null, ErrorCode.PARAMS_NULL);
        // 判断当前登录用户是否为请求的用户
        if (loginUser.getId().equals(userId)) {
            // 如果是，则返回当前登录用户的信息
            return ResultUtils.success(userService.getUserVo(loginUser));
        }
        // 如果不是，则获取请求的用户信息
        User UserInfo = userService.getById(userId);
        // 返回请求的用户信息
        return ResultUtils.success(userService.getUserVo(UserInfo));
    }

    /**
     * 修改用户密码
     * 处理用户修改密码请求，验证用户身份并更新密码
     *
     * @param userUpdatePwdRequest 包含旧密码和新密码的请求对象
     * @param request              HTTP请求对象，用于验证用户登录状态
     * @return 返回密码修改是否成功
     */
    @PostMapping("/updatePassword")
    public BaseResponse<Boolean> updatePassword(@RequestBody UserUpdatePwdRequest userUpdatePwdRequest,
                                                HttpServletRequest request) {
        // 校验登录状态
        User currentUser = userService.getLoginUser(request);
        if (currentUser == null) {
            throw new BusinessException(ErrorCode.NOT_LOGIN_ERROR);
        }

        UserVO userVo = userService.updatePassword(userUpdatePwdRequest, request);

        if (userVo == null) {
            throw new BusinessException(ErrorCode.SYSTEM_ERROR);
        }
        return ResultUtils.success(true);
    }

    /**
     * 修改用户信息
     * 处理用户信息修改请求，更新用户基本信息
     *
     * @param userUpdateRequest 包含要更新的用户信息的请求对象
     * @param request           HTTP请求对象，用于验证用户登录状态
     * @return 返回更新后的用户信息
     */
    @Transactional(rollbackFor = Exception.class)
    @PostMapping("/update")
    public BaseResponse<UserUpdateRequest> updateUser(@RequestBody UserUpdateRequest userUpdateRequest, HttpServletRequest request) {
        User loginUser = userService.getLoginUser(request);
        if (loginUser == null) {
            throw new BusinessException(ErrorCode.NOT_LOGIN_ERROR);
        }
        Long id = userUpdateRequest.getId();
        if (id == null || id < 0) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        User user = new User();
        BeanUtils.copyProperties(userUpdateRequest, user);
        boolean updateUserStatus = userService.updateById(user);
        if (updateUserStatus) {
            return ResultUtils.success(userUpdateRequest);
        } else {
            throw new BusinessException(ErrorCode.SYSTEM_ERROR);
        }
    }

    /**
     * 管理员修改用户状态
     * 仅管理员可调用，用于修改用户的状态（如启用/禁用）
     *
     * @param userUpdateRequest 包含用户ID和新状态的请求对象
     * @return 返回状态修改是否成功
     */
    @AuthCheck(mustRole = UserConstant.ADMIN_ROLE)
    @PostMapping("/updateStatus")
    public BaseResponse<Boolean> updateUserStatus(@RequestBody UserUpdateRequest userUpdateRequest) {
        Long id = userUpdateRequest.getId();
        if (id == null || id < 0) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        Integer status = userUpdateRequest.getUserStatus();
        if (status == null || status < 0) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        boolean updateUserStatus = userService.updateUserStatus(userUpdateRequest);
        if (updateUserStatus) {
            return ResultUtils.success(true);
        } else {
            throw new BusinessException(ErrorCode.SYSTEM_ERROR);
        }
    }

    /**
     * 添加新用户
     * 仅管理员可调用，用于创建新的用户账号
     *
     * @param userAddRequest 包含新用户信息的请求对象
     * @return 返回用户创建是否成功
     */
    @AuthCheck(mustRole = UserConstant.ADMIN_ROLE)
    @PostMapping("/add")
    public BaseResponse<Boolean> addUser(@RequestBody UserAddRequest userAddRequest) {
        //参数校验
        if (userAddRequest == null) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        String userAccount = userAddRequest.getUserAccount();
        String userName = userAddRequest.getUserName();
        String email = userAddRequest.getEmail();
        Integer gender = userAddRequest.getGender();
        if (gender == null || gender < 0) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        String phone = userAddRequest.getPhone();
        if (StringUtils.isAnyBlank(userAccount, userName, email, phone)) {
            throw new BusinessException(ErrorCode.DATA_NULL_ERROR);
        }
        User user = new User();
        BeanUtils.copyProperties(userAddRequest, user);
        //密码加密
        String encryptPassword = userService.getEncryptPassword(DEFAULT_PASSWORD);
        user.setUserPassword(encryptPassword);
        //保存到数据库
        boolean save = userService.save(user);
        if (!save) {
            throw new BusinessException(ErrorCode.SYSTEM_ERROR);
        }
        return ResultUtils.success(true);
    }

    /**
     * 分页查询用户列表
     * 仅管理员可调用，获取用户列表的分页数据
     *
     * @param userQueryRequest 包含分页和查询条件的请求对象
     * @return 返回用户列表的分页数据
     */
    @PostMapping("/list/page/vo")
    @AuthCheck(mustRole = UserConstant.ADMIN_ROLE)
    public BaseResponse<Page<UserVO>> listUserVOByPage(@RequestBody UserQueryRequest userQueryRequest) {
        if (userQueryRequest == null) {
            throw new BusinessException(ErrorCode.PARAMS_NULL);
        }
        int pageNum = userQueryRequest.getPageNum();
        int pageSize = userQueryRequest.getPageSize();

        Page<User> userPage = userService.page(new Page<>(pageNum, pageSize), userService.getQueryWrapper(userQueryRequest));
        Page<UserVO> userVOPage = new Page<>(pageNum, pageSize, userPage.getTotal());
        List<UserVO> userVOList = userService.getUserVoList(userPage.getRecords());
        userVOPage.setRecords(userVOList);
        return ResultUtils.success(userVOPage);
    }

    /**
     * 添加用户签到记录
     * 处理用户签到请求，记录签到状态并计算连续签到天数
     *
     * @param request HTTP请求对象，用于获取当前登录用户信息
     * @return 返回签到结果和连续签到天数
     */
    @PostMapping("/add/sign_in")
    public BaseResponse<?> addUserSignIn(HttpServletRequest request) {
        // 必须要登录才能签到
        User loginUser = userService.getLoginUser(request);
        boolean result = userService.addUserSignIn(loginUser.getId());
        if (result) {
            Map<String, Object> response = new HashMap<>();
            response.put("success", true);
            response.put("continuousDays", userService.getContinuousSignDays(loginUser.getId()));
            return ResultUtils.success(response);
        } else {
            return ResultUtils.success(false);
        }
    }

    /**
     * 获取用户签到记录
     * 获取指定年份的用户签到记录
     *
     * @param date    查询的年份（为空表示当前年份）
     * @param request HTTP请求对象，用于获取当前登录用户信息
     * @return 返回用户在指定年份的签到记录列表
     */
    @GetMapping("/get/sign_in")
    public BaseResponse<List<Integer>> getUserSignInRecord(@RequestParam(required = false)
                                                           @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate date, HttpServletRequest request) {
        // 必须要登录才能获取
        User loginUser = userService.getLoginUser(request);
        if (date == null) {
            date = LocalDate.now();
        }
        List<Integer> userSignInRecord = userService.getUserSignInRecord(loginUser.getId(), date.getYear());
        if (CollUtil.isEmpty(userSignInRecord)) {
            return ResultUtils.success(Collections.emptyList());
        }
        return ResultUtils.success(userSignInRecord);
    }

    /**
     * 批量导出用户信息
     * 仅管理员可调用，根据筛选条件导出用户信息到Excel文件
     *
     * @param userVo   包含导出筛选条件的用户视图对象
     * @param response HTTP响应对象，用于输出Excel文件
     * @throws Exception 可能抛出IO异常或业务异常
     */
    @PostMapping("/exportSelected")
    @AuthCheck(mustRole = UserConstant.ADMIN_ROLE)
    public void exportSelected(@RequestBody UserVO userVo, HttpServletResponse response) throws Exception {
        // 从请求参数中获取用户ID列表
        List<Long> ids = userVo.getIds();
        // 校验ID列表是否为空
        if (ids == null || ids.isEmpty()) {
            throw new BusinessException(ErrorCode.PARAMS_NULL);
        }
        // 获取筛选条件：用户名和用户账号
        String userName = userVo.getUserName();
        String userAccount = userVo.getUserAccount();
        // 创建查询条件构造器
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();

        // 如果用户名不为空，添加模糊查询条件
        if (StringUtils.isNotBlank(userName)) {
            queryWrapper.like(true, "userName", userName);
        }

        // 如果用户账号不为空，添加模糊查询条件
        if (StringUtils.isNotBlank(userAccount)) {
            queryWrapper.like(true, "userAccount", userAccount);
        }

        // 添加ID列表查询条件
        queryWrapper.in("id", ids);
        // 根据查询条件获取用户列表
        List<User> list = userService.list(queryWrapper);
        String date = new SimpleDateFormat("yyyy-MM-dd").format(new Date());
        String fileName = URLEncoder.encode("用户信息表", StandardCharsets.UTF_8);
        // 生成当前日期字符串
        final String FILE_NAME = date + '-' + fileName;
        // 对文件名进行URL编码，支持中文文件名
        ExcelUtil.writeWeb(FILE_NAME, User.class, list, null, response);
    }

    /**
     * 导入用户数据
     * 仅管理员可调用，从Excel文件导入用户数据
     *
     * @param file 包含用户数据的Excel文件
     * @return 返回导入操作是否成功
     * @throws Exception 可能抛出文件处理异常或业务异常
     */
    @PostMapping("/import")
    @AuthCheck(mustRole = UserConstant.ADMIN_ROLE)
    @Transactional(rollbackFor = Exception.class)
    public BaseResponse<Boolean> importData(@RequestParam("file") MultipartFile file) throws Exception {
        // 验证文件类型是否为Excel(.xlsx)
        String contentType = file.getContentType();
        if (contentType == null || !contentType.equals("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        // 从Excel文件中读取用户数据
        List<User> userList = excelUtil.importExcel(file, User.class);
        // 遍历处理每个用户
        for (User user : userList) {
            // 设置用户默认密码
            String encryptPassword = userService.getEncryptPassword(DEFAULT_PASSWORD);
            user.setUserPassword(encryptPassword);
            // 检查用户是否已存在（通过账号或ID）
            User one = userService.getOne(new QueryWrapper<User>().eq("userAccount", user.getUserAccount())
                    .or().eq("id", user.getId()));
            if (one != null) {
                throw new BusinessException(ErrorCode.PARAMS_ERROR, "用户信息已存在,请检查表格内容!");
            }
            // 保存用户信息
            boolean save = userService.save(user);
            if (!save) {
                throw new BusinessException(ErrorCode.SYSTEM_ERROR, "导入失败，请检查表格内容！");
            }
        }
        return ResultUtils.success(true);
    }
}